package com.lib.utils;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelUuid;
import android.text.TextUtils;

import androidx.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 蓝牙管理类
 * <uses-permission android:name="android.permission.BLUETOOTH" />
 * <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
 */
final public class BLeManager {
    private final UUID UUID_SERVICE_COMMON = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");
    private final UUID UUID_NOTIFY_COMMON = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb");

    private UUID mUuidService = UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb");
    private UUID mUuidNotify = UUID.fromString("0000fff1-0000-1000-8000-00805f9b34fb");
    private UUID mUuidWrite = UUID.fromString("0000fff2-0000-1000-8000-00805f9b34fb");

    private final UUID mUuidUserDescriptor = UUID.fromString("00002901-0000-1000-8000-00805f9b34fb");
    private final UUID mUuidNotificationDescriptor = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");

    private final int MAX_RECONNECT_COUNT = 3;

    public static final int BLE_TURN_ON = 0x10;
    public static final int BLE_TURN_OFF = 0x11;

    public static final int BLE_SCAN_STOP = 0x20;
    public static final int BLE_SCAN_FOUND = 0x21;

    public static final int BLE_CONNECT_SUCCESS = 0x30;
    public static final int BLE_CONNECT_FAILED = 0x31;
    public static final int BLE_DISCONNECTED = 0x32;

    public static final int BLE_ADVERTISE_SUCCESS = 0x40;
    public static final int BLE_ADVERTISE_FAILED = 0x41;
    public static final int BLE_ADVERTISE_STOPPED = 0x42;

    private static final int MSG_BLE_ON_RECV = 0x100;

    private ConcurrentHashMap<String, BluetoothGatt> mGattMap = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, Integer> mReconnectCountMap = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, BluetoothDevice> mServerDeviceList = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, BluetoothGattCharacteristic> mWriteCharacteristic = new ConcurrentHashMap<>();

    private StateCallBack mStateCallBack;
    private ArrayList<MsgCallBack> mMsgRecvCallBacks = new ArrayList<>();

    private String[] mFilterAddress;
    private volatile boolean mMustHaveName = true;
    private volatile boolean mAutoDetectService = false;
    private volatile boolean mNeedServerReconnect = false;

    private Context mContext;
    private BluetoothManager mBluetoothManager;
    private BluetoothAdapter mBluetoothAdapter;

    private volatile InnerHandler mHandler;
    private volatile BtGattCallback mBtGattCallback;
    private volatile LocalBleBroadcastReceiver mReceiver;
    private volatile ScanCallback mScanCallback;
    /* 服务端----------------------------------------------------------------------------*/
    private volatile boolean mIsServer;
    private volatile GattServerCallback mGattServerCallback;
    private volatile AdvertiseCallback mAdvertiseCallback;

    private volatile BluetoothGattServer mGattServer;
    private volatile BluetoothGattCharacteristic mCServiceNotify;
    /* ----------------------------------------------------------------------------服务端*/

    @IntDef({BLE_TURN_ON, BLE_TURN_OFF,
            BLE_SCAN_STOP,
            BLE_ADVERTISE_SUCCESS, BLE_ADVERTISE_FAILED, BLE_ADVERTISE_STOPPED})
    @Retention(RetentionPolicy.SOURCE)
    public @interface StateInt {
    }

    @IntDef({BLE_SCAN_FOUND,
            BLE_CONNECT_SUCCESS, BLE_CONNECT_FAILED, BLE_DISCONNECTED,})
    @Retention(RetentionPolicy.SOURCE)
    public @interface DeviceStateInt {
    }

    public interface StateCallBack {
        /**
         * 蓝牙状态发生变化的回调
         *
         * @param state 状态码
         */
        void onStateChanged(@StateInt int state);

        /**
         * 设备状态发生变化的回调
         *
         * @param state  状态码
         * @param device 设备 state
         */
        void onDeviceStateChanged(@DeviceStateInt int state, BluetoothDevice device);
    }

    public interface MsgCallBack {
//        void onSend(String address, byte[] bytes);

        void onRecv(String address, byte[] bytes);
    }

    private static class Inner {
        private static BLeManager sBLeManager = new BLeManager();
    }

    private BLeManager() {
    }

    public static BLeManager getInstance() {
        return Inner.sBLeManager;
    }

    public void setUUID(UUID uuidService, UUID uuidNotify, UUID uuidWrite) {
        mUuidService = uuidService;
        mUuidNotify = uuidNotify;
        mUuidWrite = uuidWrite;
    }

    /**
     * 初始化
     *
     * @return false - 失败
     */
    public boolean init(Context context) {
        mContext = context;

        if (mBluetoothAdapter != null) {
            return true;
        }
        mBluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        if (mBluetoothManager == null) {
            XLog.w("Not Support Bluetooth");
            return false;
        }
        mBluetoothAdapter = mBluetoothManager.getAdapter();
        if (mBluetoothAdapter == null) {
            XLog.w("Not Support Bluetooth!");
            return false;
        }
        mHandler = new InnerHandler();
        return true;
    }

    public BLeManager setStateCallback(StateCallBack stateCallBack) {
        mStateCallBack = stateCallBack;
        return this;
    }

    public BLeManager regMsgRecvCallBack(MsgCallBack callBack, boolean reg) {
        if (reg) {
            if (!mMsgRecvCallBacks.contains(callBack)) {
                mMsgRecvCallBacks.add(callBack);
            }
        } else {
            mMsgRecvCallBacks.remove(callBack);
        }
        XLog.i("regMsgRecvCallBack = " + mMsgRecvCallBacks);
        return this;
    }

    public BluetoothAdapter getBluetoothAdapter() {
        return mBluetoothAdapter;
    }

    public boolean isServer() {
        return mIsServer;
    }

    /**
     * 设置是否作为服务端
     *
     * @return true - 设置成功
     */
    public boolean setServer(boolean server) {
        if (server == mIsServer) {
            return true;
        }
        mIsServer = server;
        if (mIsServer) {
//            return openGattServer();
            return true;
        } else {
            return closeGattServer();
        }
    }

    public boolean isEnable() {
        return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
    }

    public boolean enable() {
        if (mBluetoothAdapter != null) {
            return mBluetoothAdapter.enable();
        }
        return false;
    }

    public boolean disable() {
        return mBluetoothAdapter != null && mBluetoothAdapter.disable();
    }

    public boolean isConnected() {
        return mServerDeviceList.size() > 0 || mGattMap.size() > 0;
    }

    public boolean isConnected(BluetoothDevice device) {
        if (mBluetoothManager == null) {
            return false;
        }
        String address = device.getAddress();
        if (mIsServer) {
            return mServerDeviceList.containsKey(address);
        } else {
            return mGattMap.containsKey(address);
        }
    }

    public boolean isCanSendMsg(BluetoothDevice device) {
        if (mBluetoothManager == null || device == null) {
            return false;
        }
        String address = device.getAddress();
        if (mIsServer) {
            return mServerDeviceList.containsKey(address);
        } else {
            return mWriteCharacteristic.containsKey(address);
        }
    }

    public boolean readRemoteRssi(BluetoothDevice device) {
        if (mBluetoothManager == null || device == null) {
            return false;
        }
        BluetoothGatt gatt = mGattMap.get(device.getAddress());
        return gatt != null && gatt.readRemoteRssi();
    }

    public List<BluetoothDevice> getConnectedDevices() {
        if (mBluetoothManager == null) {
            return null;
        }
        List<BluetoothDevice> list = new ArrayList<>();
        if (mIsServer) {
            Collection<BluetoothDevice> values = mServerDeviceList.values();
            if (values.size() > 0) {
                list.addAll(values);
            }
        } else {
            Collection<BluetoothGatt> values = mGattMap.values();
            if (values.size() > 0) {
                BluetoothGatt[] arr = values.toArray(new BluetoothGatt[]{});
                for (BluetoothGatt gatt : arr) {
                    list.add(gatt.getDevice());
                }
            }
        }
        return list;
    }

    /**
     * 开始扫描
     */
    public boolean startDiscovery(String... filterAddress) {
        if (mBluetoothAdapter == null) {
            return false;
        }
        if (mIsServer) {
            return false;
        }
        if (mReceiver == null) {
            mReceiver = new LocalBleBroadcastReceiver();
            //开启蓝牙广播监听
            IntentFilter filter = new IntentFilter();
            filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
            filter.addAction(BluetoothDevice.ACTION_FOUND);
            mContext.registerReceiver(mReceiver, filter);
        }

        mFilterAddress = filterAddress;

        XLog.i("-----------startDiscovery--------------");
        mBluetoothAdapter.startDiscovery();
        mHandler.sendEmptyMessageDelayed(BLE_SCAN_STOP, 10 * 1000L);
        return true;
    }

    public void cancelDiscovery() {
        if (mBluetoothAdapter == null) {
            return;
        }
        XLog.i("-----------cancelDiscovery--------------");
        mBluetoothAdapter.cancelDiscovery();
        if (mReceiver != null) {
            mContext.unregisterReceiver(mReceiver);
            mReceiver = null;
        }

        if (Inner.sBLeManager.mStateCallBack != null) {
            Inner.sBLeManager.mStateCallBack.onStateChanged(BLE_SCAN_STOP);
        }
    }

    public boolean startLeScan() {
        if (mBluetoothAdapter == null) {
            return false;
        }
        BluetoothLeScanner bleScanner = mBluetoothAdapter.getBluetoothLeScanner();
        if (bleScanner == null) {
            return false;
        }
        if (mScanCallback == null) {
            mScanCallback = new ScanCallback() {
                @Override
                public void onScanResult(int callbackType, ScanResult result) {
                    BluetoothDevice device = result.getDevice();
                    onFoundDevice(device);
                }

                @Override
                public void onScanFailed(int errorCode) {
                    XLog.w("errorCode = " + errorCode);
                }
            };
        }
        XLog.i("-----------startScan--------------");
        bleScanner.startScan(mScanCallback);
        mHandler.sendEmptyMessageDelayed(BLE_SCAN_STOP, 10 * 1000L);
        return true;
    }

    public void stopLeScan() {
        if (mBluetoothAdapter == null || mScanCallback == null) {
            return;
        }
        BluetoothLeScanner bleScanner = mBluetoothAdapter.getBluetoothLeScanner();
        if (bleScanner == null) {
            return;
        }
        XLog.i("-----------stopScan--------------");
        bleScanner.stopScan(mScanCallback);
        mScanCallback = null;

        if (Inner.sBLeManager.mStateCallBack != null) {
            Inner.sBLeManager.mStateCallBack.onStateChanged(BLE_SCAN_STOP);
        }
    }

    private void onFoundDevice(BluetoothDevice device) {
        String deviceName = device.getName();
        String deviceAddress = device.getAddress();
        XLog.d("BLE_FOUND: " + deviceName + "(" + deviceAddress + ")");
        if (Inner.sBLeManager.mMustHaveName && TextUtils.isEmpty(deviceName)) {
            return;
        }
//                    if (Inner.sBleManager.mHandler.mDisConnectDevice != null) {
//                        String deviceAddress = Inner.sBleManager.mHandler.mDisConnectDevice.getAddress();
//                        if (deviceAddress.equals(device.getAddress())) {
//                            XLog.w("扫描到已断设备，准备连接 ");
//                            Inner.sBleManager.mHandler.removeMessages(STOP_SCAN);
//                            Inner.sBleManager.mBluetoothAdapter.cancelDiscovery();
//                            Inner.sBleManager.mBluetoothAdapter.get().cancelDiscovery();
//                            device.connectGatt(context, false, Inner.sBleManager.mBleCallback);
//                        }
//                        return;
//                    }
        boolean contains = false;
        if (Inner.sBLeManager.mFilterAddress != null && Inner.sBLeManager.mFilterAddress.length > 0) {
            for (String filterAddress : Inner.sBLeManager.mFilterAddress) {
                String str = filterAddress.toLowerCase();
                if (deviceAddress.toLowerCase().contains(str) || deviceName.toLowerCase().contains(str)) {
                    contains = true;
                    break;
                }
            }
        } else {
            contains = true;
        }
        if (contains) {
            if (Inner.sBLeManager.mStateCallBack != null) {
                Inner.sBLeManager.mStateCallBack.onDeviceStateChanged(BLE_SCAN_FOUND, device);
            }
        }
    }

    public void connect(BluetoothDevice device) {
        connect(device, MAX_RECONNECT_COUNT);
    }

    /**
     * @param reconnectCount 允许重连的次数
     * @param device         d
     * @return false-肯定失败
     */
    public void connect(BluetoothDevice device, int reconnectCount) {
        if (mBluetoothAdapter == null || device == null) {
            XLog.w("Failed to connect...");
            if (Inner.sBLeManager.mStateCallBack != null) {
                Inner.sBLeManager.mStateCallBack.onDeviceStateChanged(BLE_CONNECT_FAILED, device);
            }
            return;
        }
        if (mIsServer) {
            if (Inner.sBLeManager.mStateCallBack != null) {
                Inner.sBLeManager.mStateCallBack.onDeviceStateChanged(BLE_CONNECT_FAILED, device);
            }
            return;
        }
        String address = device.getAddress();
        if (Inner.sBLeManager.mGattMap.containsKey(address)) {
            if (Inner.sBLeManager.mStateCallBack != null) {
                Inner.sBLeManager.mStateCallBack.onDeviceStateChanged(BLE_CONNECT_SUCCESS, device);
            }
            return;
        }
        cancelDiscovery();
        stopLeScan();

        mReconnectCountMap.put(address, reconnectCount);

        if (mBtGattCallback == null) {
            mBtGattCallback = new BtGattCallback();
        }
        device.connectGatt(mContext, false, mBtGattCallback);
    }

    private boolean openGattServer() {
        XLog.i(Thread.currentThread().getName());
        if (mBluetoothAdapter == null) {
            return false;
        }
        if (mGattServer != null) {
            return true;
        }
        if (mGattServerCallback == null) {
            mGattServerCallback = new GattServerCallback();
        }
        mGattServer = mBluetoothManager.openGattServer(mContext, mGattServerCallback);
        if (mGattServer == null) {
            XLog.w("openGattServer error");
            return false;
        }
        XLog.i("openGattServer success");
        addService();
        return true;
    }

    private void addService() {
        XLog.i("addService->" + Thread.currentThread().getName());
        BluetoothGattService gattService = new BluetoothGattService(mUuidService, BluetoothGattService.SERVICE_TYPE_PRIMARY);
        int permissions = BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE;
        {// 创建特征-通知
            int properties = BluetoothGattCharacteristic.PROPERTY_READ
                    | BluetoothGattCharacteristic.PROPERTY_NOTIFY;
            mCServiceNotify = new BluetoothGattCharacteristic(mUuidNotify, properties, permissions);

            BluetoothGattDescriptor d1 = new BluetoothGattDescriptor(mUuidUserDescriptor, permissions);
            mCServiceNotify.addDescriptor(d1);
            BluetoothGattDescriptor d2 = new BluetoothGattDescriptor(mUuidNotificationDescriptor, permissions);
            mCServiceNotify.addDescriptor(d2);
            gattService.addCharacteristic(mCServiceNotify);
        }
        {// 创建特征-写
            int properties = BluetoothGattCharacteristic.PROPERTY_WRITE
                    | BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE;
            BluetoothGattCharacteristic cWrite = new BluetoothGattCharacteristic(mUuidWrite, properties, permissions);
            cWrite.addDescriptor(new BluetoothGattDescriptor(mUuidUserDescriptor, permissions));
            gattService.addCharacteristic(cWrite);
        }
        // 添加服务
        mGattServer.addService(gattService);
    }

    private boolean closeGattServer() {
        if (mGattServer != null) {
            mGattServer.clearServices();
            mGattServer.close();
            mGattServer = null;
        }
        mCServiceNotify = null;
        mGattServerCallback = null;
        return true;
    }

    public boolean isAdvertising() {
        return mAdvertiseCallback != null;
    }

    public void startAdvertising() {
        if (mBluetoothAdapter == null) {
            if (Inner.sBLeManager.mStateCallBack != null) {
                Inner.sBLeManager.mStateCallBack.onStateChanged(BLE_ADVERTISE_FAILED);
            }
            return;
        }
        BluetoothLeAdvertiser bleAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
        if (bleAdvertiser == null) {
            if (Inner.sBLeManager.mStateCallBack != null) {
                Inner.sBLeManager.mStateCallBack.onStateChanged(BLE_ADVERTISE_FAILED);
            }
            return;
        }
        if (!mIsServer) {
            if (Inner.sBLeManager.mStateCallBack != null) {
                Inner.sBLeManager.mStateCallBack.onStateChanged(BLE_ADVERTISE_FAILED);
            }
            return;
        }
        AdvertiseSettings settings = new AdvertiseSettings.Builder()
                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
                .setConnectable(true)
//                .setTimeout(10000)
                .build();
        AdvertiseData data = new AdvertiseData.Builder()
                .setIncludeDeviceName(true)
                .setIncludeTxPowerLevel(true)
                .addServiceUuid(new ParcelUuid(mUuidService))
                .build();

        if (mAdvertiseCallback == null) {
            mAdvertiseCallback = new AdvertiseCallback() {
                @Override
                public void onStartSuccess(AdvertiseSettings settingsInEffect) {/*main*/
                    super.onStartSuccess(settingsInEffect);
                    openGattServer();
                    if (Inner.sBLeManager.mStateCallBack != null) {
                        Inner.sBLeManager.mStateCallBack.onStateChanged(BLE_ADVERTISE_SUCCESS);
                    }
                }

                @Override
                public void onStartFailure(int errorCode) {/*main*/
                    super.onStartFailure(errorCode);
                    XLog.w("errorCode:" + errorCode);
                    if (Inner.sBLeManager.mStateCallBack != null) {
                        Inner.sBLeManager.mStateCallBack.onStateChanged(BLE_ADVERTISE_FAILED);/*onStartFailure*/
                    }
                }
            };
        }
        XLog.i("-----------startAdvertising--------------");
        bleAdvertiser.startAdvertising(settings, data, mAdvertiseCallback);
//        mHandler.sendEmptyMessageDelayed(BLE_SCAN_STOP, 10 * 1000L);
    }

    public void stopAdvertising() {
        if (mBluetoothAdapter == null || mAdvertiseCallback == null) {
            return;
        }
        BluetoothLeAdvertiser bleAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
        if (bleAdvertiser == null) {
            return;
        }
        XLog.i("-----------stopAdvertising--------------");
        bleAdvertiser.stopAdvertising(mAdvertiseCallback);
        mAdvertiseCallback = null;

        if (Inner.sBLeManager.mStateCallBack != null) {
            Inner.sBLeManager.mStateCallBack.onStateChanged(BLE_ADVERTISE_STOPPED);/*stopAdvertising*/
        }
    }

    private void onServicesDiscovered(String address) {
        XLog.i("-----------onServicesDiscovered--------------");
        BluetoothGatt gatt = mGattMap.get(address);
        if (gatt == null) {
            return;
        }

        List<BluetoothGattService> services = gatt.getServices();
        for (BluetoothGattService service : services) {
            XLog.i(service.getUuid() + (service.getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY ? "(基础服务)" : "(用户服务)"));
            List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
            for (BluetoothGattCharacteristic characteristic : characteristics) {
                UUID uuid = characteristic.getUuid();
                XLog.i("------------" + uuid);
                int properties = characteristic.getProperties();
                if ((properties & BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
                    XLog.i("---读");
                }
                if ((properties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0
                        || (properties & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0) {
                    XLog.i("---写");
                    mWriteCharacteristic.put(address, characteristic);
                }
                if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
                    XLog.i("---通知");

                    gatt.setCharacteristicNotification(characteristic, true);
                    byte[] bs = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
                    writeDescriptor(gatt, characteristic, bs);
                }
                if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0) {
                    XLog.i("---指示");

                    gatt.setCharacteristicNotification(characteristic, true);
                    byte[] bs = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
                    writeDescriptor(gatt, characteristic, bs);
                }
            }
        }
    }

    private void cfgDesignatedService(String address) {
        XLog.i("-----------cfgDesignatedService--------------");
        BluetoothGatt gatt = mGattMap.get(address);
        if (gatt == null) {
            return;
        }
        //根据UUID来修改指定的特征值
        BluetoothGattService service = gatt.getService(mUuidService);
        if (service == null) {
            BluetoothGattService gattService = gatt.getService(UUID_SERVICE_COMMON);
            if (gattService != null) {
                XLog.i("通用服务存在:" + gattService);
                BluetoothGattCharacteristic cCommonNotify = gattService.getCharacteristic(UUID_NOTIFY_COMMON);
                if (cCommonNotify != null) {
                    byte[] bs = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
                    writeDescriptor(gatt, cCommonNotify, bs);
                }
            }
        } else {
            XLog.i("指定服务存在:" + service);
            BluetoothGattCharacteristic cWrite = service.getCharacteristic(mUuidWrite);
            if (cWrite != null) {
                XLog.i("指定特征存在-写:" + service);
                mWriteCharacteristic.put(address, cWrite);
            }
            BluetoothGattCharacteristic cNotify = service.getCharacteristic(mUuidNotify);
            if (cNotify != null) {
                XLog.i("指定特征存在-通知:");
                boolean notification = gatt.setCharacteristicNotification(cNotify, true);
                if (notification) {
                    byte[] bs = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
                    writeDescriptor(gatt, cNotify, bs);
                }
            }
        }
    }

    private void writeDescriptor(BluetoothGatt gatt, BluetoothGattCharacteristic notifyCharacteristic, byte[] bs) {
        BluetoothGattDescriptor descriptor = notifyCharacteristic.getDescriptor(mUuidNotificationDescriptor);
        if (descriptor != null) {
            descriptor.setValue(bs);
            gatt.writeDescriptor(descriptor);
        }
    }

    public boolean sendData(String address, byte[] rawBytes) {
//        if (mMsgRecvCallBacks != null && mMsgRecvCallBacks.size() > 0) {
//            Runnable runnable = () -> {
//                for (MsgCallBack callBack : mMsgRecvCallBacks) {
//                    callBack.onSend(address, rawBytes);
//                }
//            };
//            ThreadPoolUtils.getInstance().execute(runnable);
//        }
        int maxMsgLen = 512;
        byte[] bytes = null;

        int index = 0;
        if (rawBytes.length > maxMsgLen) {
            bytes = new byte[maxMsgLen];
            while (index + maxMsgLen <= rawBytes.length) {
                System.arraycopy(rawBytes, index, bytes, 0, bytes.length);
                index = index + bytes.length;

                if (mIsServer) {
                    sendToClient(address, bytes);
                } else {
                    sendToServer(address, bytes);
                }
            }
        }
        if (bytes == null) {
            bytes = rawBytes;
        } else if (index < rawBytes.length) {
            int size = rawBytes.length - index;
            bytes = new byte[size];
            System.arraycopy(rawBytes, index, bytes, 0, bytes.length);
        }

        if (mIsServer) {
            sendToClient(address, bytes);
        } else {
            sendToServer(address, bytes);
        }
        return true;
    }

    private boolean sendToServer(String address, byte[] bytes) {
        boolean isSendOk = false;
        if (TextUtils.isEmpty(address)) {
            Collection<BluetoothGatt> gatts = mGattMap.values();
            for (BluetoothGatt gatt : gatts) {
                if (gatt == null) {
                    continue;
                }
                address = gatt.getDevice().getAddress();
                BluetoothGattCharacteristic characteristic = mWriteCharacteristic.get(address);
                if (characteristic != null) {
                    XLog.i("发给" + address);
                    boolean ret = characteristic.setValue(bytes);
                    if (ret) {
                        ret = gatt.writeCharacteristic(characteristic);
                        if (ret && !isSendOk) {//只要有一个设备发送成功那就是成功
                            isSendOk = true;
                        }
                    } else {
                        XLog.w("setValue error");
                    }
                }
            }
        } else {
            BluetoothGattCharacteristic characteristic = mWriteCharacteristic.get(address);
            if (characteristic == null) {
                XLog.w("write characteristic is null, address=" + address);
            } else {
                BluetoothGatt gatt = mGattMap.get(address);
                if (gatt == null) {
                    XLog.w("gatt is null, address=" + address);
                } else {
                    XLog.i("发给指定" + address);
                    isSendOk = characteristic.setValue(bytes);
                    if (isSendOk) {
                        isSendOk = gatt.writeCharacteristic(characteristic);
                    }
                }
            }
        }
        return isSendOk;
    }

    private boolean sendToClient(String address, byte[] bytes) {
        if (mBluetoothManager == null || mGattServer == null
                || mBluetoothAdapter == null || mCServiceNotify == null) {
            return false;
        }
        boolean isSendOk = false;
        if (TextUtils.isEmpty(address)) {
            Collection<BluetoothDevice> values = mServerDeviceList.values();
            XLog.i("list = " + values);

            for (BluetoothDevice device : values) {
                XLog.i("发给" + device.getAddress());
                boolean ret = mCServiceNotify.setValue(bytes);
                if (ret) {
                    ret = mGattServer.notifyCharacteristicChanged(device, mCServiceNotify, false);
                    if (ret && !isSendOk) {//只要有一个设备发送成功那就是成功
                        isSendOk = true;
                    }
                } else {
                    XLog.w("setValue error.");
                }
            }
        } else {
            BluetoothDevice device = mServerDeviceList.get(address);
            if (device == null) {
                XLog.w("not connect, address=" + address);
            } else {
                XLog.i("发给指定" + address);
                isSendOk = mCServiceNotify.setValue(bytes);
                if (isSendOk) {
                    isSendOk = mGattServer.notifyCharacteristicChanged(device, mCServiceNotify, false);
                }
            }
        }
        return isSendOk;
    }

    private void refreshGattCache(BluetoothGatt gatt) {
        try {
            Method refresh = BluetoothGatt.class.getMethod("refresh");
            refresh.setAccessible(true);
            refresh.invoke(gatt);
            XLog.i("---------------refreshGattCache----------------------");
        } catch (Exception e) {
            XLog.w("------------refreshGattCache Error--------------------");
            e.printStackTrace();
        }
    }

    private void disconnectGatt(String address) {
        BluetoothGatt gatt = mGattMap.get(address);
        if (gatt != null) {
            gatt.abortReliableWrite();
            gatt.disconnect();
            gatt.close();
//            refreshGattCache(gatt);
        }
    }

    public void disconnect(BluetoothDevice device) {
        if (mBluetoothAdapter == null) {
            return;
        }
        if (mIsServer) {
            if (mGattServer != null) {
                mGattServer.cancelConnection(device);
            }
            mServerDeviceList.remove(device.getAddress());
        } else {
            String address = device.getAddress();
            mReconnectCountMap.remove(address);
            disconnectGatt(address);
            mGattMap.remove(address);
        }

        if (Inner.sBLeManager.mStateCallBack != null) {
            Inner.sBLeManager.mStateCallBack.onDeviceStateChanged(BLE_DISCONNECTED, device);
        }
    }

    public void disconnectAll() {
        XLog.i("-----------disconnectAll--------------");
        Collection<BluetoothGatt> gatts = mGattMap.values();
        for (BluetoothGatt gatt : gatts) {
            BluetoothDevice device = gatt.getDevice();
            String address = device.getAddress();

            disconnectGatt(address);
        }
        mGattMap.clear();

        mReconnectCountMap.clear();
        mWriteCharacteristic.clear();

        Collection<BluetoothDevice> devices = mServerDeviceList.values();
        for (BluetoothDevice device : devices) {
            mGattServer.cancelConnection(device);
        }
        mServerDeviceList.clear();
    }

    public void release() {
        XLog.i("-----------release--------------");
        stopAdvertising();
        disconnectAll();
        closeGattServer();
        cancelDiscovery();
        stopLeScan();
        mMsgRecvCallBacks.clear();

        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }
        mIsServer = false;

        mStateCallBack = null;

        mFilterAddress = null;
        mMustHaveName = true;
        mAutoDetectService = false;

        mContext = null;
        mBluetoothManager = null;
        mBluetoothAdapter = null;

        mBtGattCallback = null;
    }

    private void sendToHandler(int what, Object obj) {
        if (mHandler == null) {
            return;
        }
        Message message = Message.obtain();
        message.what = what;
        message.obj = obj;
        mHandler.sendMessage(message);
    }

    //<editor-fold desc="Inner Class">
    private class GattServerCallback extends BluetoothGattServerCallback {
        @Override
        public void onMtuChanged(BluetoothDevice device, int mtu) {
            super.onMtuChanged(device, mtu);
            XLog.i("GattServer.mtu = " + mtu);
        }

        @Override
        public void onServiceAdded(int status, BluetoothGattService service) {
            super.onServiceAdded(status, service);
            XLog.i("onServiceAdded status=" + status);
        }

        @Override
        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {/*子线程*/
            super.onConnectionStateChange(device, status, newState);
            XLog.w("GattServerCallback.device:" + device.getName() + "," + device.getAddress() + ", newState = " + newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                boolean connect = mGattServer.connect(device, false);
                if (connect) {
                    mServerDeviceList.put(device.getAddress(), device);
                    sendToHandler(BLE_CONNECT_SUCCESS, device);
                } else {
                    sendToHandler(BLE_CONNECT_FAILED, device);
                }
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                if (mNeedServerReconnect && mGattServer.connect(device, false)) {
                    mServerDeviceList.put(device.getAddress(), device);
                    sendToHandler(BLE_CONNECT_SUCCESS, device);
                } else {
                    mServerDeviceList.remove(device.getAddress());
                    sendToHandler(BLE_DISCONNECTED, device);
                }
            }
        }

        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic,
                                                 boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {/*子线程*/
            super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
            XLog.i(characteristic.getUuid() + ".Recv2: " + value.length);

            if (responseNeeded) {
                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
            }
//
//            Bundle bundle = new Bundle();
//            bundle.putString("address", address);
//            bundle.putByteArray("message", value);
//            sendToHandler(MSG_BLE_ON_READ, bundle);
            if (Inner.sBLeManager.mMsgRecvCallBacks != null) {
                String address = device.getAddress();
                for (MsgCallBack callBack : Inner.sBLeManager.mMsgRecvCallBacks) {
                    callBack.onRecv(address, value);
                }
            }
        }

        @Override
        public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
            XLog.i("responseNeeded = " + responseNeeded);
            if (responseNeeded) {
                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, value);
            }
        }
    }

    private static class BtGattCallback extends BluetoothGattCallback {
        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            super.onReadRemoteRssi(gatt, rssi, status);
            XLog.i("rssi:" + rssi + ", status:" + status);
        }

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { /*连接状态变化,这里是子线程*/
            super.onConnectionStateChange(gatt, status, newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                gatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                BluetoothDevice device = gatt.getDevice();
                Inner.sBLeManager.sendToHandler(BLE_DISCONNECTED, device);
            } else {
//                XLog.i("BluetoothGattServerCallback:" + gatt + ", status=" + status + ",newState=" + newState);
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) { /*服务发现,这里也是子线程*/
            super.onServicesDiscovered(gatt, status);
            BluetoothDevice device = gatt.getDevice();

            if (status == BluetoothGatt.GATT_SUCCESS) {
                String address = device.getAddress();
                if (!Inner.sBLeManager.mGattMap.containsKey(address)) {
                    Inner.sBLeManager.mGattMap.put(address, gatt);
                }
                if (Inner.sBLeManager.mAutoDetectService) {
                    Inner.sBLeManager.onServicesDiscovered(address);
                } else {
                    Inner.sBLeManager.cfgDesignatedService(address);
                }
                Inner.sBLeManager.sendData(address, "12345678".getBytes());
                Inner.sBLeManager.sendToHandler(BLE_CONNECT_SUCCESS, device);
            } else {
                Inner.sBLeManager.sendToHandler(BLE_CONNECT_FAILED, device);
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {/*子线程*/
            super.onCharacteristicChanged(gatt, characteristic);
            String address = gatt.getDevice().getAddress();
            byte[] value = characteristic.getValue();
            XLog.i("Recv1: " + value.length);

//            Bundle bundle = new Bundle();
//            bundle.putString("address", address);
//            bundle.putByteArray("message", value);
//            Inner.sBleManager.sendToHandler(MSG_BLE_ON_READ, bundle);
            if (Inner.sBLeManager.mMsgRecvCallBacks != null) {
                for (MsgCallBack callBack : Inner.sBLeManager.mMsgRecvCallBacks) {
                    callBack.onRecv(address, value);
                }
            }
        }
    }

    private static class InnerHandler extends Handler {
        private BluetoothDevice mDisConnectDevice;

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BLE_CONNECT_SUCCESS: {
                    XLog.i("BLE_CONNECT_OK:");
                    BluetoothDevice device = (BluetoothDevice) msg.obj;
                    String address = device.getAddress();

                    if (mDisConnectDevice != null) {
                        String disAddress = mDisConnectDevice.getAddress();
                        if (disAddress.equals(address)) {
                            mDisConnectDevice = null;
                            Inner.sBLeManager.mReconnectCountMap.put(address, Inner.sBLeManager.MAX_RECONNECT_COUNT);

                            String deviceName = device.getName();
//                            deviceName = SPUtils.getSP().getString(address, deviceName);
                            String tip = String.format("%s 已重连成功", deviceName);
                            XLog.i(tip);
                        }
                    }

                    if (Inner.sBLeManager.mStateCallBack != null) {
                        Inner.sBLeManager.mStateCallBack.onDeviceStateChanged(BLE_CONNECT_SUCCESS, device);
                    }
                }
                break;
                case BLE_CONNECT_FAILED: {
                    XLog.w("BLE_CONNECT_FAILED:");
                    BluetoothDevice device = (BluetoothDevice) msg.obj;

                    if (Inner.sBLeManager.mStateCallBack != null) {
                        Inner.sBLeManager.mStateCallBack.onDeviceStateChanged(BLE_CONNECT_FAILED, device);
                    }
                }
                break;
                case BLE_DISCONNECTED: {
                    XLog.w("BLE_DISCONNECTED:");
                    BluetoothDevice device = (BluetoothDevice) msg.obj;

                    Inner.sBLeManager.disconnect(device);

                    String address = device.getAddress();
                    Integer reconnectCount = Inner.sBLeManager.mReconnectCountMap.get(address);

                    if (reconnectCount != null && reconnectCount > 0) { /*若有重连次数*/
                        mDisConnectDevice = device;
                        int count = reconnectCount - 1;
                        Inner.sBLeManager.connect(mDisConnectDevice, count);
                        XLog.i("connect..." + count);
//                        Inner.sBleManager.mReconnectStatus = STATUS_RECONNECTING;
//                        Inner.sBleManager.startDiscovery(Inner.sBleManager.mStateCallBack, 10000);
                    } else {
                        if (Inner.sBLeManager.mStateCallBack != null) {
                            Inner.sBLeManager.mStateCallBack.onDeviceStateChanged(BLE_DISCONNECTED, device);
                        }
                    }
                }
                break;
                case BLE_SCAN_STOP:
                    if (Inner.sBLeManager.mIsServer) {
                        Inner.sBLeManager.stopAdvertising();
                    } else {
                        Inner.sBLeManager.cancelDiscovery();
                        Inner.sBLeManager.stopLeScan();
                    }
                    break;
                case MSG_BLE_ON_RECV:
                    Bundle bundle = (Bundle) msg.obj;
                    String address = bundle.getString("address", "");
                    byte[] bytes = bundle.getByteArray("message");

                    if (Inner.sBLeManager.mMsgRecvCallBacks != null) {
                        for (MsgCallBack callBack : Inner.sBLeManager.mMsgRecvCallBacks) {
                            callBack.onRecv(address, bytes);
                        }
                    }
                    break;
            }
        }
    }

    private static class LocalBleBroadcastReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action == null) {
                return;
            }
            switch (action) {
                case BluetoothAdapter.ACTION_STATE_CHANGED:/*蓝牙适配器状态*/
                    int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                    switch (state) {
                        case BluetoothAdapter.STATE_ON:
                            if (Inner.sBLeManager.mStateCallBack != null) {
                                Inner.sBLeManager.mStateCallBack.onStateChanged(BLE_TURN_ON);
                            }
                            break;
                        case BluetoothAdapter.STATE_OFF:
                            Inner.sBLeManager.release();
                            if (Inner.sBLeManager.mStateCallBack != null) {
                                Inner.sBLeManager.mStateCallBack.onStateChanged(BLE_TURN_OFF);
                            }
                            break;
                    }
                    break;
                case BluetoothDevice.ACTION_FOUND:/* 这里是主线程 */
                    BluetoothDevice device = intent.getParcelableExtra(android.bluetooth.BluetoothDevice.EXTRA_DEVICE);
                    Inner.sBLeManager.onFoundDevice(device);
                    break;
            }
        }
    }
//</editor-fold>
}